<template>
  <div class="home">
    <el-row :gutter="20">
      <el-col :span="19">
        <div style="width: 100%;">
          <mavon-editor ref="md" v-html="html"></mavon-editor>
        </div>
      </el-col>
      <el-col :span="4">
        <ArticleTree :html="html"/>
      </el-col>
    </el-row>
  </div>
</template>

<script setup>

import ArticleTree from "@/components/ArticleTree.vue";
import {onMounted, ref} from "vue";

const html = ref("");

onMounted(() => {
  html.value = "<h1><a id=\"_0\"></a>线程池</h1>\n" +
      "<h2><a id=\"_2\"></a>线程池引入</h2>\n" +
      "<p>所谓线程池，通俗来讲，就是一个管理线程的池子。它可以容纳多个线程，其中的线程可以反复 利用，省去了频繁创建线程对象的操作。 在 Java 并发编程框架中的线程池是运用场景最多的技术，几乎所有需要异步或并发执行任务的 程序都可以使用线程池。在开发过程中，合理地使用线程池能够带来至少以下4个好处：</p>\n" +
      "<ul>\n" +
      "<li>降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗；</li>\n" +
      "<li>提高响应速度。当任务到达时，任务可以不需要等到线程创建就能立即执行；</li>\n" +
      "<li>提高线程的可管理性。线程是稀缺资源，如果无限制地创建，不仅会消耗系统资源，还会 降低系统的稳定性，使用线程池可以进行统一分配、调优和监控。</li>\n" +
      "<li>提供更强大的功能，比如延时定时线程池；</li>\n" +
      "</ul>\n" +
      "<h2><a id=\"Executors_11\"></a>Executors</h2>\n" +
      "<h3><a id=\"_13\"></a>概述</h3>\n" +
      "<p>Executors 是一个Java中的工具类。提供工厂方法来创建不同类型的线程池。</p>\n" +
      "<p>核心概念：这四个线程池的本质都是ThreadPoolExecutor对象:</p>\n" +
      "<ul>\n" +
      "<li>newFiexedThreadPool(int Threads) : 创建固定数目线程的线程池。</li>\n" +
      "<li>newCachedThreadPool() : 创建一个可缓存的线程池，调用execute 将重用以前构 造的线程（如果线程可用）。如果没有可用的线程，则创建一个新线程并添加到池中。终 止并从缓存中移除那些已有 60 秒钟未被使用的线程。</li>\n" +
      "<li>newSingleThreadExecutor() : 创建一个单线程化的Executor。</li>\n" +
      "<li>newScheduledThreadPool(int corePoolSize) : 创建一个支持定时及周期性的 任务执行的线程池，多数情况下可用来替代Timer类。</li>\n" +
      "</ul>\n" +
      "<h3><a id=\"Executors_24\"></a>Executors缺陷</h3>\n" +
      "<p>在阿里巴巴Java开发手册中明确指出，不允许使用Executors创建线程池，这是因为使用Executors创建线程池可能会导致OOM(OutOfMemory ,内存溢出)。</p>\n" +
      "<h2><a id=\"_28\"></a>优雅的创建线程池</h2>\n" +
      "<h3><a id=\"_30\"></a>正确挑选方法</h3>\n" +
      "<p>避免使用Executors创建线程池，主要是避免使用其中的默认实现，那么我们可以自己直接调 用 ThreadPoolExecutor 的构造函数来自己创建线程池。在创建的同时，给 BlockQueue 指定 容量就可以了。</p>\n" +
      "<pre><div class=\"hljs\"><code class=\"lang-java\"><span class=\"hljs-keyword\">public</span> <span class=\"hljs-title function_\">ThreadPoolExecutor</span><span class=\"hljs-params\">(<span class=\"hljs-type\">int</span> corePoolSize,\n" +
      "                          <span class=\"hljs-type\">int</span> maximumPoolSize,\n" +
      "                          <span class=\"hljs-type\">long</span> keepAliveTime,\n" +
      "                          TimeUnit unit,\n" +
      "                          BlockingQueue&lt;Runnable&gt; workQueue,\n" +
      "                          ThreadFactory threadFactory,\n" +
      "                          RejectedExecutionHandler handler)</span>{}\n" +
      "</code></div></pre>\n" +
      "<ul>\n" +
      "<li>\n" +
      "<p>corePoolSize ：线程池中的核心线程数。指定线程数回一直存在与线程池中，除非设置了allowCoreThreadTimeOut参数。当创建完成之后就会准备好等待接收异步任务去执行；</p>\n" +
      "</li>\n" +
      "<li>\n" +
      "<p>maximumPoolSize ：最大线程数。当请求的线程超过核心线程数时，将会扩充线程数量到最大线程数，但不会无限扩充，达到控制资源的效果；</p>\n" +
      "</li>\n" +
      "<li>\n" +
      "<p>keepAliveTime ：非核心线程的存活时间。如果当前存活的线程数量大于核心线程数</p>\n" +
      "</li>\n" +
      "<li>\n" +
      "<p>corePoolSize，则会释放空闲的线程直到线程数回到核心线程数corePoolSize；</p>\n" +
      "</li>\n" +
      "<li>\n" +
      "<p>unit ：keepAliveTime 参数的时间单位，如TimeUnit.SECONDS；</p>\n" +
      "</li>\n" +
      "<li>\n" +
      "<p>workQueue ：阻塞队列。用于保存多余的任务，如果任务很多，就会将多的任务存放进队列中，只要有空闲的线程就会去队列中取出新的任务执行直到队列为空；</p>\n" +
      "</li>\n" +
      "<li>\n" +
      "<p>threadFactory ：线程池工厂，标识线程，即为线程起一个具有意义的名称，可自定义；</p>\n" +
      "</li>\n" +
      "<li>\n" +
      "<p>handler ：拒绝策略。如果阻塞队列满了，就会按照我们指定的拒绝策略拒绝后续任务，默认为丢弃任务。</p>\n" +
      "</li>\n" +
      "</ul>\n" +
      "<h3><a id=\"_60\"></a>线程池配置类</h3>\n" +
      "<p>在开发过程中一般会将线程池的创建抽取成一个配置类，其中的各类参数则会配置在配置文件中去。 这里有个细节，就是创建线程池的时候并不会立马准备好 corePoolSize 数量的线程来准备接收任务，而是要等到有任务提交时才会启动。</p>\n" +
      "<p>这里使用了prestartCoreThread 方法在初始化线程池的时候开启一个核心线程，避免在执行异步操作的时 候初始化核心线程耗时巨大（可自行尝试，在后面的例子中因为加上了这一方法，接口的耗时减少了50倍）</p>\n" +
      "<pre><div class=\"hljs\"><code class=\"lang-java\"><span class=\"hljs-meta\">@Configuration</span>\n" +
      "\n" +
      "<span class=\"hljs-keyword\">public</span> <span class=\"hljs-keyword\">class</span> <span class=\"hljs-title class_\">ThreadPoolConfig</span> {\n" +
      "    <span class=\"hljs-meta\">@Bean</span>\n" +
      "\n" +
      "    <span class=\"hljs-keyword\">public</span> ThreadPoolExecutor <span class=\"hljs-title function_\">threadPoolExecutor</span><span class=\"hljs-params\">(\n" +
      "        <span class=\"hljs-meta\">@Value(&quot;${thread.pool.coreSize}&quot;)</span> Integer coreSize,\n" +
      "        <span class=\"hljs-meta\">@Value(&quot;${thread.pool.maxSize}&quot;)</span> Integer maxSize,\n" +
      "        <span class=\"hljs-meta\">@Value(&quot;${thread.pool.keepalive}&quot;)</span> Integer keepalive,\n" +
      "        <span class=\"hljs-meta\">@Value(&quot;${thread.pool.blockQueueSize}&quot;)</span> Integer blockQueueSize\n" +
      "    )</span> {\n" +
      "        <span class=\"hljs-type\">ThreadPoolExecutor</span> <span class=\"hljs-variable\">executor</span> <span class=\"hljs-operator\">=</span> <span class=\"hljs-keyword\">new</span> <span class=\"hljs-title class_\">ThreadPoolExecutor</span>(\n" +
      "            coreSize,\n" +
      "            maxSize,\n" +
      "            keepalive,\n" +
      "            TimeUnit.SECONDS,\n" +
      "            <span class=\"hljs-keyword\">new</span> <span class=\"hljs-title class_\">ArrayBlockingQueue</span>&lt;&gt;(blockQueueSize),\n" +
      "            Executors.defaultThreadFactory(),\n" +
      "            <span class=\"hljs-keyword\">new</span> <span class=\"hljs-title class_\">ThreadPoolExecutor</span>.AbortPolicy()\n" +
      "        );\n" +
      "        executor.prestartCoreThread();\n" +
      "        <span class=\"hljs-keyword\">return</span> executor;\n" +
      "    }\n" +
      "}\n" +
      "</code></div></pre>\n" +
      "<h2><a id=\"_93\"></a>线程池执行流程</h2>\n" +
      "<p><img src=\"http://118.89.125.143:9000/lzh-blog/img_image-202311061639520931699260103946.png\" alt=\"image-20231106163952093\" /></p>\n" +
      "<p>下面详细介绍线程池的详细运行流程：</p>\n" +
      "<ol>\n" +
      "<li>线程池创建，但是并不会立马准备好 corePoolSize 数量的线程来准备接收任务，线程 并不会立即启动，而是要等到有任务提交时才会启动。除非调用了</li>\n" +
      "</ol>\n" +
      "<p>prestartCoreThread/prestartAllCoreThreads 事先启动核心线程：</p>\n" +
      "<p>​\t\t1.1. prestartCoreThread：Starts a core thread, causing it to idly wait for work. This overrides the default policy of starting core threads \tonly when new t asks are executed；</p>\n" +
      "<p>​\t\t1.2. prestartAllCoreThreads：Starts all core threads。</p>\n" +
      "<ol start=\"2\">\n" +
      "<li>任务到来，用准备好的 corePoolSize 个空闲线程执行：</li>\n" +
      "</ol>\n" +
      "<p>​\t\t2.1. 核心线程数已满，就将再进来的任务放入阻塞队列中，期间如果运行中的线程小于 核心线程数时，就会去阻塞队列中获取任务\t\t执行；</p>\n" +
      "<p>​\t\t2.2. 阻塞队列已满，就会创建新线程去执行阻塞队列中的任务，但最大只能创建到最大线程数 maximumPoolSize ；</p>\n" +
      "<p>​\t\t2.3. 存活且运行的线程数达到最大线程数 maximumPoolSize ，即线程已满时，根据 设定的拒绝策略 handler 来对后来任务进行相应\t\t处理；</p>\n" +
      "<p>​\t\t2.4. 当所有线程都执行完，在指定时间 keepAliveTime 之后，将会自动销毁线程， 最终保持在 corePoolSize 大小。</p>\n" +
      "<ol start=\"3\">\n" +
      "<li>在线程创建过程中，所有的线程都由指定的工厂 threadFactory 进行创建，并为线程设 置标识，即起名。</li>\n" +
      "</ol>\n" +
      "<h3><a id=\"_119\"></a>线程池场景模拟</h3>\n" +
      "<blockquote>\n" +
      "<p>一个线程池corePoolSize为7，maximumPoolSize为20，阻塞队列最大50，100并发进来怎么分配的？ 答案：先有7个线程能够直接处理7个任务，接下来50个进入队列排队，再多开13个继续执 行。此时所有线程池和阻塞队列都已满，但只有70个被安排上，剩下的30个走设定好的拒绝策略 进行相对应操作。</p>\n" +
      "</blockquote>\n" +
      "<p><img src=\"http://118.89.125.143:9000/lzh-blog/img_image-202311061641143161699260103946.png\" alt=\"image-20231106164114316\" /></p>\n";
})

</script>
